package com.heima.wemedia.service.impl;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.common.constants.KafkaConstant;
import com.heima.common.constants.NewsConstant;
import com.heima.common.constants.Constant;
import com.heima.common.constants.NewsResultConstant;
import com.heima.feign.client.ApArticleClient;
import com.heima.feign.client.TaskClient;
import com.heima.model.acticle.dtos.ArticleDto;
import com.heima.model.common.dtos.PageResponseResult;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.common.enums.NewsStatusEnum;
import com.heima.model.schedule.dtos.Task;
import com.heima.model.wemedia.dtos.WmNewsDto;
import com.heima.model.wemedia.dtos.WmNewsPageDto;
import com.heima.model.wemedia.pojos.WmMaterial;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.model.wemedia.pojos.WmNewsMaterial;
import com.heima.utils.threadLocal.UserIdThreadLocal;
import com.heima.wemedia.mapper.WmChannelMapper;
import com.heima.wemedia.mapper.WmMaterialMapper;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.mapper.WmUserMapper;
import com.heima.wemedia.service.ITextAndImageService;
import com.heima.wemedia.service.IWmNewsMaterialService;
import com.heima.wemedia.service.IWmNewsService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.http.HttpStatus;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 自媒体图文内容信息表 服务实现类
 * </p>
 *
 * @author chana
 * @since 2024-08-15
 */
@Service
@Slf4j
public class WmNewsServiceImpl extends ServiceImpl<WmNewsMapper, WmNews> implements IWmNewsService {

    @Resource
    private WmNewsMapper wmNewsMapper;

    @Resource
    private WmMaterialMapper wmMaterialMapper;

    @Resource
    private IWmNewsMaterialService wmNewsMaterialService;

    @Resource
    private ITextAndImageService textAndImageService;
    
    @Resource
    private KafkaTemplate<String,String> kafkaTemplate;

    @Resource
    private TaskClient taskClient;

    /**
     * 提交文章
     *
     * @param dto
     * @return
     */
    @Transactional
    @Override
    public ResponseResult submit(WmNewsDto dto) {

        //1.
        WmNews wmNews = new WmNews();
        BeanUtils.copyProperties(dto, wmNews);
        LocalDateTime now = LocalDateTime.now();
        wmNews.setCreatedTime(now);
        wmNews.setSubmitedTime(now);
        wmNews.setUserId(UserIdThreadLocal.getUserId());
        wmNews.setStatus(NewsStatusEnum.setNewsStatusEnum(dto.getStatus()));

        List<String> images = selectOfImage(wmNews.getContent());

        //3.类型为自动
        typeAuto(dto,wmNews,images);
        //2.
        wmNewsMapper.insert(wmNews);
        //4.保存关系表
        //4.1 主图引用
        if (!CollectionUtils.isEmpty(dto.getImages())){
            saveNewsMaterial(wmNews.getId(),dto.getImages(), NewsConstant.TYPE_TETILE);
        }
        //4.2 内容引用
        if (!CollectionUtils.isEmpty(images)){
            saveNewsMaterial(wmNews.getId(),images,NewsConstant.TYPE_CONTENT);
        }
        //审核文章
        textAndImageService.articeleModeration(wmNews);
        //使用MQ来通知文章上线
        if (StringUtils.isEmpty(wmNews.getPublishTime())){
            submitTask(wmNews);
        }else {
            sendArticle(wmNews.getArticleId());
        }

        return ResponseResult.okResult(null);
    }

    private void submitTask(WmNews wmNews) {
        Task task = new Task();
        task.setParameters(wmNews.getArticleId()+"");
        task.setTaskType(10);
        task.setPriority(1);
        //
        ZonedDateTime zonedDateTime = wmNews.getPublishTime().atZone(ZoneId.systemDefault());
        Date date = Date.from(zonedDateTime.toInstant());
        task.setExecuteTime(date);
        taskClient.autoTask(task);
    }

    /**
     * 通知文章上线
     */
    @Async
    public void sendArticle(Long id) {
        kafkaTemplate.send(KafkaConstant.TOPIC_ARTICLE_UP,id.toString());
    }


    /**
     * 分页查询
     * @param dto
     * @return
     */
    @Override
    public ResponseResult listAndPage(WmNewsPageDto dto) {
        //1.
        Page<WmNews> page = new Page<>(dto.getPage(), dto.getSize());

        LambdaQueryWrapper<WmNews> wrapper = Wrappers.<WmNews>lambdaQuery()
                .eq(null != dto.getStatus(), WmNews::getStatus, dto.getStatus())
                .eq(null != dto.getChannelId(), WmNews::getChannelId, dto.getChannelId())
                .between(null != dto.getBeginPubDate() || null != dto.getEndPubDate(),
                        WmNews::getPublishTime, dto.getBeginPubDate(), dto.getEndPubDate())
                .like(!StringUtils.isEmpty(dto.getKeyword()),WmNews::getTitle,dto.getKeyword())
                .orderByDesc(WmNews::getCreatedTime);
        page(page,wrapper);

        ResponseResult result = new PageResponseResult(dto.getPage(), dto.getSize(),(int)page.getTotal());

        result.setData(page.getRecords());

        return result;
    }

    /**
     * 逻辑删除文章
     * @param id
     * @return
     */
    @Override
    @Transactional
    public ResponseResult delNews(Integer id) {
        //
        wmNewsMapper.deleteById(id);
        //
        Wrappers.<WmNews>lambdaUpdate()
                .set(WmNews::getEnable,0)
                .eq(WmNews::getId, id);
        wmNewsMaterialService.update();

        return ResponseResult.okResult(null);
    }

    /**
     * 根据iD查找文章
     * @param id
     * @return
     */
    @Override
    public ResponseResult selectById(Integer id) {
        //
        return ResponseResult.okResult(wmNewsMapper.selectById(id));
    }

    /**
     * 使用MQ通知客户端下架/上架文章
     * @param dto
     * @return
     */
    @Override
    public ResponseResult downOrUp(WmNewsDto dto) {
        WmNews wmNews = getById(dto.getId());
        if (StringUtils.isEmpty(wmNews)){
            log.info("文章不存在");
            return ResponseResult
                    .okResult(AppHttpCodeEnum.PARAM_INVALID.getCode(), NewsResultConstant.RESULT_NOT_EXIST);
        }
        if (StringUtils.isEmpty(wmNews.getArticleId())){
            log.info("文章ID不可缺少");
            return ResponseResult
                    .okResult(AppHttpCodeEnum.PARAM_INVALID.getCode(), NewsResultConstant.RESULT_NOT_ID);
        }
        if (!NewsStatusEnum.STATUS_NEWS_NINE.equals(wmNews.getStatus())){
            log.info("当前文章不处于发布状态，不能下载");
            return ResponseResult
                    .okResult(AppHttpCodeEnum.PARAM_INVALID.getCode(), NewsResultConstant.RESULT_NOT_UP);
        }
        //
        wmNews.setEnable(dto.getEnable());
        wmNewsMapper.updateById(wmNews);
        //使用MQ来通知app端下架
        sendEnable(wmNews);
        return ResponseResult.okResult(null);
    }

    /**
     * 使用MQ通知客户端下架/上架文章
     */
    @Async
    public void sendEnable(WmNews wmNews) {
        Map<String,String> msg = new HashMap<>();
        msg.put(KafkaConstant.MSG_ENABLE_DOWN_ID,wmNews.getArticleId()+"");
        msg.put(KafkaConstant.MSG_ENABLE_DOWN_ENABLE,wmNews.getEnable()+"");

        kafkaTemplate.send(KafkaConstant.TOPIC_ENABLE_DOWN, JSON.toJSONString(msg));
    }

    /**
     * 保存关系表
     * @param newId
     * @param images
     * @param type
     */
    @Transactional
    public void saveNewsMaterial(Integer newId, List<String> images, int type) {
        LambdaQueryWrapper<WmMaterial> queryWrapper = Wrappers
                .<WmMaterial>lambdaQuery().in(WmMaterial::getUrl, images);
        List<WmMaterial> materials = wmMaterialMapper.selectList(queryWrapper);

        List<WmNewsMaterial> materialList = materials.stream().map(wmMaterial -> {
            WmNewsMaterial wmNewsMaterial = new WmNewsMaterial();
            wmNewsMaterial.setMaterialId(wmMaterial.getId());
            wmNewsMaterial.setNewsId(newId);
            wmNewsMaterial.setType(type);
            wmNewsMaterial.setOrd(NewsConstant.ORD);
            return wmNewsMaterial;
        }).collect(Collectors.toList());

        wmNewsMaterialService.saveBatch(materialList);
    }

    /**
     * 数据获取
     * @param wmNews
     * @param images
     */
    private void typeAuto(WmNewsDto dto,WmNews wmNews, List<String> images) {
        if (wmNews.getType().equals(NewsConstant.NEWS_TYPE_IS_EMPTY)) {
            //3.1在文中查找图片
            int size = images.size();
            if (CollectionUtils.isEmpty(images)) {
                wmNews.setType(NewsConstant.NEWS_TYPE_NULL);
            } else if (size >= 3) {
                List<String> collect = images.stream().limit(Constant.NUMBER_THREE).collect(Collectors.toList());
                String image = StringUtils.collectionToCommaDelimitedString(collect);

                wmNews.setType(NewsConstant.NEWS_TYPE_MORE);
                wmNews.setImages(image);
            }else {
                List<String> collect = images.stream().limit(Constant.NUMBER_ONE).collect(Collectors.toList());
                String image = StringUtils.collectionToCommaDelimitedString(collect);

                wmNews.setType(NewsConstant.NEWS_TYPE_ONE);
                wmNews.setImages(image);
            }
        }else if (wmNews.getType().equals(NewsConstant.NEWS_TYPE_NULL)){
            wmNews.setImages(null);
        }else {
            wmNews.setImages(StringUtils.collectionToCommaDelimitedString(dto.getImages()));
        }
    }

    /**
     * 获取文中的图片
     * @param content
     * @return
     */
    private List<String> selectOfImage(String content) {
        //1.
        List<Map> list = JSONArray.parseArray(content, Map.class);
        //2.
        List<String> images = new ArrayList<>();
        list.stream().map(map -> {
            String image = (String) map.get(NewsConstant.JSON_TYPE_ONE);
            String text = (String) map.get(NewsConstant.JSON_TYPE_TWO);
            if (NewsConstant.JSON_VALUE_ONE.equals(image)) {
                images.add(text);
            }
            return text;
        }).collect(Collectors.toList());

        return images;
    }
}
